/*
 * Title:        CloudScheduler Toolkit
 * Description:  a Toolkit for Modeling and Simulation of Job Scheduling and Resource Provisioning in Cloud System
 * Licence:      GPL - http://www.gnu.org/copyleft/gpl.html
 * Author:       Fuhui Wu
 *
 * Copyright (c) 2013-2014, The National University of Defense Technology, China
 */

package org.nudt.jCloud.simulation;

import java.util.ArrayList;
import java.util.List;

import org.nudt.jCloud.example.resourceStealing1.BatchJobScheduler;
import org.nudt.jCloud.example.resourceStealing2.PreemptionJobScheduler;
import org.nudt.jCloud.infrastructure.Slot;
import org.nudt.jCloud.jobScheduler.JobScheduler;
import org.nudt.jCloud.resourceManager.ResManager;
import org.nudt.jCloud.resourceScaler.ResourceScaler;
import org.nudt.jCloud.util.Log;

public class UserBroker extends SimEntity{
	private List<User> userList;
	private Framework frwk;
	private int RM_Mode;	//0: reservation mode; 1: share state mode; 2: others.
	
	public UserBroker(String name, int RM_Mode) {
		super(name);
		setUserList(new ArrayList<User>());
		setRM_Mode(RM_Mode);
	}
	
	public void init(JobScheduler jobScheduler,
			ResourceScaler resourceScaler){
		createFrwk(jobScheduler, resourceScaler);
	}
		
	public void reset(){
		setFrwk(null);
		userList.clear();
	}
	
	public void addUser(User user){
		userList.add(user);
		user.setUserBroker(this);
	}
		
	public void createFrwk(JobScheduler jobScheduler, ResourceScaler resourceScaler){
		Framework frwk = new Framework();
		frwk.setUserBroker(this);
		frwk.setJobScheduler(jobScheduler);
		frwk.setResourceScaler(resourceScaler);
		jobScheduler.setFrwk(frwk);
		resourceScaler.setFrwk(frwk);
		setFrwk(frwk);
	}
	
	public boolean hasUnSubmittedXJob(){
		for(int i=0; i<userList.size(); ++i){
			if(userList.get(i).getSubmittedXJobCount()<userList.get(i).getWl().size()){
				return true;
			}
		}
		return false;
	}

	@Override
	public void startEntity() {
		
	}

	@SuppressWarnings("unchecked")
	@Override
	public void processEvent(SimEvent event) {
		switch(event.getTag()){
			case SIMTag.REGISTER_USERBROKER_ACK:
				processUserRegisterAck((ResManager)event.getData());
				break;
			case SIMTag.UPDATE_OR_SUBMIT_JOB:
				processNextEvent((double)event.getData());
				break;
			case SIMTag.SCALE_RESOURCE_ACK:
				processScaleResACK((ScaleData)event.getData());
				break;
			case SIMTag.RESOURCE_COMMIT_ACK:
				getFrwk().getJobScheduler().processResCommitACK((VirtSlotAlloc)event.getData());
				break;
			case SIMTag.PREEMPT_STOLEN_SLOT:
				BatchJobScheduler jobScheduler1 = (BatchJobScheduler)getFrwk().getJobScheduler();
				jobScheduler1.preemptSlot((List<Slot>)event.getData());
				break;
			case SIMTag.TO_STEAL_RESOURCE:
				BatchJobScheduler jobScheduler2 = (BatchJobScheduler)getFrwk().getJobScheduler();
				jobScheduler2.stealResource((List<Slot>)event.getData());
				break;
			case SIMTag.PREEMPT_SLOT:
				PreemptionJobScheduler jobScheduler = (PreemptionJobScheduler)getFrwk().getJobScheduler();
				jobScheduler.preemptSlot((List<Slot>)event.getData());
				break;
			default:
				processOtherEvent(event);
				break;
		}
	}

	private void processNextEvent(double nextTime) {
		getFrwk().getJobScheduler().processNextEvent(nextTime);
		
	}
	
	private void processUserRegisterAck(ResManager rm) {
		this.getFrwk().setResManager(rm);
		Log.println("framework registered to resource manager: "+rm.getName());
		this.getFrwk().getJobScheduler().nextEvent();
	}
	
	private void processScaleResACK(ScaleData scaleData){
		getFrwk().getJobScheduler().scheduleJob(scaleData.getRequestData());				
	}
	
	/**
	 * @return the frwk
	 */
	public Framework getFrwk() {
		return frwk;
	}

	/**
	 * @param frwk the frwk to set
	 */
	public void setFrwk(Framework frwk) {
		this.frwk = frwk;
	}

	public List<User> getUserList() {
		return userList;
	}

	public void setUserList(List<User> userList) {
		this.userList = userList;
	}

	public int getRM_Mode() {
		return RM_Mode;
	}

	public void setRM_Mode(int rM_Mode) {
		RM_Mode = rM_Mode;
	}

}
